package top.codef.config;

import javax.money.MonetaryAmount;
import javax.money.format.AmountFormatContext;
import javax.money.format.AmountFormatContextBuilder;
import javax.money.format.MonetaryAmountFormat;

import org.apache.commons.lang3.StringUtils;
import org.javamoney.moneta.spi.FastMoneyAmountFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import top.codef.formatterfactories.MoneyFormatterFactory;
import top.codef.money.MercuryMonetaryFormat;
import top.codef.money.MercuryMoneyParserDelegate;
import top.codef.money.MercuryMoneyPrinter;
import top.codef.money.interfaces.MercuryMonetaryAmountFormat;
import top.codef.money.interfaces.MoneyPrinter;
import top.codef.properties.MercuryProperties;
import top.codef.serializers.AbstractMoneyDeserializer;
import top.codef.serializers.AbstractMoneySerializer;
import top.codef.serializers.DefaultMoneyDeserializer;
import top.codef.serializers.DefaultMoneySerializer;

@Configuration
@EnableConfigurationProperties({ MercuryProperties.class })
public class MoneyFormatConfig {

	@Autowired
	private MercuryProperties mercuryProperties;

	@Bean
	public MoneyFormatterFactory fastMoneyFormatterFactory(MercuryMonetaryAmountFormat mercuryMonetaryAmountFormat) {
		MoneyFormatterFactory factory = new MoneyFormatterFactory(mercuryProperties, mercuryMonetaryAmountFormat);
		return factory;
	}

	@Bean
	@ConditionalOnMissingBean
	public AbstractMoneySerializer<MonetaryAmount> serializer(MonetaryAmountFormat amountFormat) {
		AbstractMoneySerializer<MonetaryAmount> ser = new DefaultMoneySerializer(MonetaryAmount.class,
				mercuryProperties, amountFormat);
		return ser;
	}

	@Bean
	@ConditionalOnMissingBean
	public AbstractMoneyDeserializer<MonetaryAmount> deserializer(MercuryMonetaryAmountFormat amountFormat) {
		AbstractMoneyDeserializer<MonetaryAmount> deserializer = new DefaultMoneyDeserializer(MonetaryAmount.class,
				mercuryProperties, amountFormat);
		return deserializer;
	}

	@Bean
	@ConditionalOnMissingBean
	public MoneyPrinter moneyPrinter(AmountFormatContext amountFormatContext) {
		MoneyPrinter moneyPrinter = new MercuryMoneyPrinter(amountFormatContext.getText("pattern"),
				amountFormatContext);
		return moneyPrinter;
	}

	@Bean
	@ConditionalOnMissingBean
	public MercuryMoneyParserDelegate mercuryMoneyParserDelegate(AmountFormatContext context) {
		MercuryMoneyParserDelegate mercuryMoneyParserDelegate = new MercuryMoneyParserDelegate(context);
		return mercuryMoneyParserDelegate;
	}

	@Bean
	@ConditionalOnMissingBean
	public MercuryMonetaryAmountFormat monetaryFormat(AmountFormatContext amountFormatContext,
			MercuryMoneyParserDelegate mercuryMoneyParserDelegate, MoneyPrinter printer) {
		MercuryMonetaryAmountFormat mercuryMonetaryFormat = new MercuryMonetaryFormat(amountFormatContext, printer,
				mercuryMoneyParserDelegate);
		return mercuryMonetaryFormat;
	}

	@Bean
	@ConditionalOnMissingBean
	public AmountFormatContext amountFormatContext() {
		AmountFormatContextBuilder builder = AmountFormatContextBuilder.of(mercuryProperties.currentLocale());
		String pattern = mercuryProperties.getPattern();
		if (StringUtils.isNoneBlank(pattern))
			builder.set("pattern", mercuryProperties.getPattern());
		return builder.setMonetaryAmountFactory(new FastMoneyAmountFactory()).build();
	}
}
